package com.kewu.common.global;

import com.kewu.common.enums.ErrorCodeEnum;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

@Getter
@Setter
@NoArgsConstructor
@Slf4j
@ToString
public class ResponseData<T> {

    private String code;

    private String msg;

    private T data;

    public ResponseData(String code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> ResponseData<T> success() {
        return ErrorCodeEnum.SUCCESS.resp();
    }

    public static <T> ResponseData<T> success(T data) {
        ResponseData<T> responseData = ErrorCodeEnum.SUCCESS.resp();
        responseData.setData(data);
        return responseData;
    }


    public boolean isSuccess() {
        return ErrorCodeEnum.SUCCESS.getErrCode().equals(this.code);
    }

    public static <T> ResponseData error(CustomException e) {
        return e.resp();
    }

    public static <T> ResponseData error(ErrorCodeEnum errorCodeEnum) {
        return errorCodeEnum.resp();
    }

    public static <T> ResponseData error(String code, String msg) {
        return new ResponseData(code, msg, null);
    }

    public static <T> ResponseData error(ErrorCodeEnum errorCodeEnum, String msg) {
        return errorCodeEnum.resp(msg);
    }

    public static <T> ResponseData error() {
        return ErrorCodeEnum.SYSTEM_ERROR.resp();
    }

    public static <T> ResponseData error(Exception e) {
        if (e instanceof CustomException) {
            CustomException exception = (CustomException) e;
            return exception.resp();
        } else {
            return ErrorCodeEnum.SYSTEM_ERROR.resp();
        }
    }


    public <R> R handleSuccess(Function<T, R> function) {
        return isSuccess() ? function.apply(this.data) : null;
    }

    public ResponseData onSuccess(Consumer<T> consumer) {
        if (isSuccess()) {
            consumer.accept(this.data);
        }
        return this;
    }

    public ResponseData onError(Consumer<T> consumer) {
        if (!isSuccess()) {
            consumer.accept(this.data);
        }
        return this;
    }

    public <R> R handleError(Function<T, R> function) {
        return !isSuccess() ? function.apply(this.data) : null;
    }

    public <X extends RuntimeException> void onErrorThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (!isSuccess()) {
            throw exceptionSupplier.get();
        }
    }
}